home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2007 December / PCWKCD1207B.iso / Blogowanie poza sfera / Flock 0.9.1.3 stable / flock-0.9.1.3.en-US.win32.exe / flock / components / flockBlogService.js < prev    next >
Text File  |  2007-10-12  |  47KB  |  1,460 lines

  1. // BEGIN FLOCK GPL
  2. // 
  3. // Copyright Flock Inc. 2005-2007
  4. // http://flock.com
  5. // 
  6. // This file may be used under the terms of of the
  7. // GNU General Public License Version 2 or later (the "GPL"),
  8. // http://www.gnu.org/licenses/gpl.html
  9. // 
  10. // Software distributed under the License is distributed on an "AS IS" basis,
  11. // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. // for the specific language governing rights and limitations under the
  13. // License.
  14. // 
  15. // END FLOCK GPL
  16. //
  17.  
  18. // Constants
  19. const Cc = Components.classes;
  20. const Ci = Components.interfaces;
  21. const Cr = Components.results;
  22.  
  23. const EDITOR_URL = "chrome://browser/content/flock/blog/editor.xul"
  24.  
  25. const DEBUG = false;                // set to false to suppress debug messages
  26. const FLOCK_BLOG_CID                = Components.ID('{70b6c92b-8f34-4d1c-9057-e03e10770b96}');
  27.  
  28. const OLD_SHELF_RDF_FILE            = "flock_shelf.rdf";
  29. const OLD_BLOG_RDF_FILE             = "flock_blog.rdf";
  30. const OLD_BLOG_RDF_FILE_RELIC       = "flock_blog_old.rdf";
  31.  
  32. const FLOCK_BLOG_CONTRACTID         = '@flock.com/flock-blog;1';
  33.  
  34. const FLOCK_DRAFTS_ROOT             = 'http://flock.com/rdf#DraftsRoot';
  35. const FLOCK_RECOVERY_ROOT           = 'http://flock.com/rdf#RecoveryRoot';
  36. const FLOCK_UNPUBLISHED_ROOT        = 'http://flock.com/rdf#UnpublishedRoot';
  37.  
  38. const BLOG_CONTENT_FILE      = 'blogdrafts.sqlite';
  39.  
  40. var gBlogStorage   = null;
  41.  
  42. function BlogAPIDetector() {
  43.   this.mReq = null;
  44.   this.mTitle = null;
  45. }
  46.  
  47.  
  48. BlogAPIDetector.prototype.getTitle =
  49. function() {
  50.   return this.mTitle;
  51. }
  52.  
  53.  
  54. BlogAPIDetector.prototype.doRequest =
  55. function(listener, url, processor) {
  56.   var inst = this;
  57.   var rootUrl = 'http://'+url.split('/')[2];
  58.   this.mReq = Cc['@mozilla.org/xmlextras/xmlhttprequest;1'].createInstance(Ci.nsIXMLHttpRequest);
  59.   this.mReq.onreadystatechange = function (aEvt) {
  60.     try {
  61.       if(inst.mReq.readyState == 4) {
  62.         if(inst.mReq.status == 200) {
  63.           // debug(inst.mReq.responseText + "\n");
  64.           try {
  65.             processor(listener, rootUrl, inst);
  66.           }
  67.           catch(e) {
  68.             debug("Error "+e+" "+e.fileName+" line "+e.lineNumber+"\n");
  69.             listener.onError(e);
  70.           }
  71.         }
  72.         else {
  73.           debug("\nRESPONSE\n" + inst.mReq.responseText);
  74.           listener.onError(inst.mReq.status);
  75.         }
  76.       }
  77.     }
  78.     catch(e) {
  79.       debug("Error "+e+" "+e.fileName+" line "+e.lineNumber+"\n");
  80.       listener.onError(-1);
  81.     }
  82.   }
  83.   this.mReq.open('GET', url, true);
  84.   this.mReq.send(null); 
  85. }
  86.  
  87.  
  88. BlogAPIDetector.prototype.onHomePage =
  89. function (listener, rootUrl, inst)
  90. {
  91.   // The following code is to clean up dirty html to make it parser
  92.   // friendly
  93.  
  94.   var req = inst.mReq;          
  95.   var text = req.responseText;
  96.   text = text.replace(/[\r\n]/g,"");
  97.        
  98.   if(text.match(/<title.*>(.+?)</)) {
  99.     inst.mTitle = RegExp.$1;
  100.   }
  101.  
  102.   var linkObj = function () {
  103.   }
  104.  
  105.   linkObj.prototype = {
  106.     href:null,
  107.     rel:null,
  108.     type:null,
  109.     title:null,
  110.     QueryInterface: function (iid) {
  111.       if (!iid.equals(Ci.flockIBlogLink)) 
  112.           throw Cr.NS_ERROR_NO_INTERFACE;
  113.       return this;
  114.     }
  115.   }
  116.  
  117.   var linklist = new Array();
  118.  
  119.   var R = /<link.+?>/g;
  120.   var ar = R.exec(text);
  121.   while(ar) {
  122.     var cur = ar[0] + "";
  123.     var link = new linkObj();
  124.     if(cur.match(/href=\"(.+?)\"/)) {
  125.       link.href = RegExp.$1;
  126.     }
  127.     if(cur.match(/rel=\"(.+?)\"/)) {
  128.       link.rel = RegExp.$1;
  129.     }
  130.     if(cur.match(/title=\"(.+?)\"/)) {
  131.       link.title = RegExp.$1;
  132.     }
  133.     if(cur.match(/type=\"(.+?)\"/)) {
  134.       link.type = RegExp.$1;
  135.     }
  136.     linklist.push(link);
  137.     ar = R.exec(text);
  138.   }
  139.  
  140.   var blogService = Cc[FLOCK_BLOG_CONTRACTID].getService(Ci.flockIBlogService);
  141.   var accountList = new Array();
  142.   var webServices = blogService.services;
  143.   while(webServices.hasMoreElements()) {
  144.     var service = webServices.getNext();
  145.     service.QueryInterface(Ci.flockICustomBlogWebService);
  146.     // Clone the array because our simpleEnumerator destroy it
  147.     var linklistClone = new Array();
  148.     for (i = 0; i < linklist.length; i++)
  149.       linklistClone[i] = linklist[i];
  150.     var account = service.detectAccount(rootUrl, simpleEnumerator(linklistClone));
  151.     if (account) {
  152.       debug(" ==> we found support for "+service.shortName+"\n");
  153.       accountList.push(account);
  154.     }
  155.     else {
  156.       debug(" xxx "+service.shortName+" support not found for this blog\n");
  157.     }
  158.   }
  159.  
  160.   // Let's look in the RSD before we use something else
  161.   var rsd = null;
  162.   for (i = 0; i < linklist.length; i++) {
  163.     var link = linklist[i];
  164.     if (link.title=="RSD" || link.type=="application/rsd+xml") {
  165.       debug("We found a RSD!\n"+link.href+"\n");
  166.       rsd = link;
  167.     }
  168.   }
  169.   if (rsd) {
  170.     var xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance (Ci.nsIXMLHttpRequest);
  171.     xhr.open ('GET', rsd.href, true);
  172.  
  173.     xhr.onreadystatechange = function (aEvent) {
  174.       if (xhr.readyState == 4) {
  175.         if (xhr.status != 200) {
  176.           // Error
  177.           listener.onResult(null);
  178.           return;
  179.         }
  180.         var dom = xhr.responseXML;
  181.         if(!dom) {
  182.           // FIXME: Parse responseText is responseXML is not present (= bad XML)
  183.           //var parser = new DOMParser();
  184.           //dom = parser.parseFromString(req.responseText,"text/xml");
  185.           debug("No dom!!\n");
  186.           listener.onResult(null);
  187.           return;
  188.         }
  189.         var apis = dom.getElementsByTagName("api");
  190.         var prefApi = null;
  191.         var apiList = [];
  192.         for(var i=0;i<apis.length;++i) {
  193.           var api = {
  194.             api: apis[i].getAttribute("name").toLowerCase().replace(/\s/g,""),
  195.             apiLink: apis[i].getAttribute("apiLink"),
  196.             preferred: apis[i].getAttribute("preferred").toLowerCase(),
  197.             blogid: apis[i].getAttribute("blogID")
  198.           }
  199.           apiList.push(api);
  200.           if (api.preferred == 'true')
  201.             prefApi = api;
  202.         }
  203.         if (prefApi) {
  204.           var svc = blogService.getAPIFromShortname(prefApi.api);
  205.           debug("prefApi: looking for the service having shortname {"+prefApi.api+"}\n");
  206.           if (svc) {
  207.             listener.onResult(prefApi);
  208.             return;
  209.           }
  210.         }
  211.         while (apiList.length > 0) {
  212.           var currentApi = apiList.shift();
  213.           debug("looking for the service having shortname {"+currentApi.api+"}\n");
  214.           var svc = blogService.getAPIFromShortname(currentApi.api);
  215.           if (svc) {
  216.             listener.onResult(currentApi);
  217.             return;
  218.           }
  219.         }
  220.         // We couldn't find any supported API in the RSD. Loop in what we had before?
  221.         listener.onResult(null);
  222.       }
  223.     }
  224.     xhr.send (null);
  225.   }
  226.   else { // No RSD
  227.     if (accountList.length > 0) {
  228.       // Return the first account in the list
  229.       listener.onResult(accountList[0]); 
  230.     }
  231.     else {
  232.       listener.onResult(null); 
  233.     }
  234.   }
  235. }
  236.  
  237.  
  238. BlogAPIDetector.prototype.detect =
  239. function(listener, url)
  240. {
  241.   this.doRequest(listener, url, this.onHomePage);
  242. }
  243.  
  244. function BlogDraft () {
  245. }
  246.  
  247. BlogDraft.prototype = {
  248.   getInterfaces: function (count) {
  249.     var interfaceList = [Components.interfaces.flockIBlogDraft, Components.interfaces.nsIClassInfo];
  250.     count.value = interfaceList.length;
  251.     return interfaceList;
  252.   },
  253.   QueryInterface: function (iid) {
  254.     if (!iid.equals(Components.interfaces.flockIBlogDraft))
  255.       throw Components.results.NS_ERROR_NO_INTERFACE;
  256.     return this;
  257.   },
  258.   getHelperForLanguage: function (count) {return null;}
  259. }
  260.  
  261.  
  262. function createStatement(dbconn, sql) {
  263.   var stmt = dbconn.createStatement(sql);
  264.   var wrapper = Cc["@mozilla.org/storage/statement-wrapper;1"]
  265.     .createInstance(Ci.mozIStorageStatementWrapper);
  266.  
  267.   wrapper.initialize(stmt);
  268.   return wrapper;
  269. }
  270.  
  271. function BlogStorage() {
  272.   var dbfile = Cc['@mozilla.org/file/directory_service;1']
  273.     .getService(Ci.nsIProperties).get('ProfD', Ci.nsIFile);
  274.   dbfile.append(BLOG_CONTENT_FILE);
  275.  
  276.   var storageService = Cc['@mozilla.org/storage/service;1']
  277.     .getService(Ci.mozIStorageService);
  278.   this._DBConn = storageService.openDatabase(dbfile);
  279.  
  280.   var drafts_schema = "id INTEGER PRIMARY KEY, lastupdate INTEGER, title STRING, " +
  281.                       "content STRING, tags STRING, blog STRING DEFAULT ''";
  282.  
  283.   var recovery_schema = 'id INTEGER PRIMARY KEY, lastupdate INTEGER, title STRING, ' +
  284.                         'content STRING, tags STRING';
  285.  
  286.   try {
  287.     this._DBConn.createTable('drafts', drafts_schema);
  288.     this._DBConn.createTable('recovery', recovery_schema);
  289.   }
  290.   catch (e) { }
  291.  
  292.   this._getDraftsFrom = createStatement(this._DBConn,
  293.     'SELECT * FROM drafts WHERE blog = :blog');
  294.   this._getDraft = createStatement(this._DBConn,
  295.     'SELECT * FROM drafts WHERE id = :id');
  296.   this._replaceDraft = createStatement(this._DBConn,
  297.     'REPLACE INTO drafts (id, lastupdate, title, content, tags) ' +
  298.     'VALUES (:id, :lastupdate, :title, :content, :tags)');
  299.   this._removeDraft = createStatement(this._DBConn,
  300.     'DELETE FROM drafts where id = :id');
  301.   this._setDraftBlog = createStatement(this._DBConn,
  302.     'UPDATE drafts SET blog=:blog WHERE id=:id');
  303.  
  304.   this._replaceRecovery = createStatement(this._DBConn,
  305.     'REPLACE INTO recovery (id, lastupdate, title, content, tags) ' +
  306.     'VALUES (:id, :lastupdate, :title, :content, :tags)');
  307.   this._removeRecovery = createStatement(this._DBConn,
  308.     'DELETE FROM recovery where id = :id');
  309.   this._getAllRecovery = createStatement(this._DBConn,
  310.     'SELECT * FROM recovery');
  311.   this._emptyRecovery = createStatement(this._DBConn,
  312.     'DELETE FROM recovery');
  313. }
  314.  
  315. BlogStorage.prototype = {
  316.   deleteDraft: function BS_deleteDraft(id) {
  317.     this._removeDraft.params.id = id;
  318.     this._removeDraft.step();
  319.     this._removeDraft.reset();
  320.   },
  321.   deleteRecovery: function BS_deleteRecovery(id) {
  322.     this._removeRecovery.params.id = id;
  323.     this._removeRecovery.step();
  324.     this._removeRecovery.reset();
  325.   },
  326.   emptyRecovery: function BS_emptyRecovery() {
  327.     this._emptyRecovery.step();
  328.     this._emptyRecovery.reset();
  329.   },
  330.   saveDraft: function FS_saveDraft(id, lastupdate, title, content, tags) {
  331.     var pp = this._replaceDraft.params;
  332.     pp.id = id;
  333.     pp.lastupdate = lastupdate;
  334.     pp.title = title;
  335.     pp.content = content;
  336.     pp.tags = tags;
  337.     this._replaceDraft.step();
  338.     this._replaceDraft.reset();
  339.   },
  340.   setDraftBlog: function FS_setDraftBlog(id, blog) {
  341.     var pp = this._setDraftBlog.params;
  342.     pp.id = id;
  343.     pp.blog = blog;
  344.     this._setDraftBlog.step();
  345.     this._setDraftBlog.reset();
  346.   },
  347.   saveRecovery: function FS_saveRecovery(id, lastupdate, title, content, tags) {
  348.     var pp = this._replaceRecovery.params;
  349.     pp.id = id;
  350.     pp.lastupdate = lastupdate;
  351.     pp.title = title;
  352.     pp.content = content;
  353.     pp.tags = tags;
  354.     this._replaceRecovery.step();
  355.     this._replaceRecovery.reset();
  356.   },
  357.   getDraftsFrom: function FS_getDraftsFrom(blog) {
  358.     var result = [];
  359.     this._getDraftsFrom.reset();
  360.     var pp = this._getDraftsFrom.params;
  361.   
  362.     pp.blog = blog;
  363.     while (this._getDraftsFrom.step()) {
  364.       var draft = new BlogDraft();
  365.       draft.id = this._getDraftsFrom.row['id'];
  366.       draft.lastupdate = this._getDraftsFrom.row['lastupdate'];
  367.       draft.title = this._getDraftsFrom.row['title'];
  368.       draft.content = this._getDraftsFrom.row['content'];
  369.       draft.tags = this._getDraftsFrom.row['tags'];
  370.       result.push(draft);
  371.     }
  372.     this._getDraftsFrom.reset();
  373.  
  374.     return result;
  375.   },
  376.   getAllRecovery: function FS_getAllRecovery() {
  377.     var result = [];
  378.     this._getAllRecovery.reset();
  379.     while (this._getAllRecovery.step()) {
  380.       var recovery = new BlogDraft();
  381.       recovery.id = this._getAllRecovery.row['id'];
  382.       recovery.lastupdate = this._getAllRecovery.row['lastupdate'];
  383.       recovery.title = this._getAllRecovery.row['title'];
  384.       recovery.content = this._getAllRecovery.row['content'];
  385.       recovery.tags = this._getAllRecovery.row['tags'];
  386.       result.push(recovery);
  387.     }
  388.     this._getAllRecovery.reset();
  389.  
  390.     return result;
  391.   },
  392.   getDraft: function FS_getDraft(draftid) {
  393.     var draft = null;
  394.  
  395.     this._getDraft.reset();
  396.     this._getDraft.params.id = draftid;
  397.  
  398.     if (this._getDraft.step()) {
  399.       draft = new BlogDraft();
  400.       draft.id = this._getDraft.row['id'];
  401.       draft.lastupdate = this._getDraft.row['lastupdate'];
  402.       draft.title = this._getDraft.row['title'];
  403.       draft.content = this._getDraft.row['content'];
  404.       draft.tags = this._getDraft.row['tags'];
  405.     }
  406.     
  407.     this._getDraft.reset();
  408.     return draft;
  409.   },
  410.   beginTransaction: function FS_beginTransation() {
  411.     this._DBConn.beginTransaction();
  412.   },
  413.   commitTransaction: function FS_commitTransation() {
  414.     this._DBConn.commitTransaction();
  415.   },
  416.   rollbackTransaction: function FS_rollbackTransation() {
  417.     this._DBConn.rollbackTransaction();
  418.   },
  419.   _getData: function FS__getData(id, stmt, field) {
  420.     stmt.reset();
  421.     stmt.params.id = id;
  422.  
  423.     var data = null;
  424.     if (stmt.step())
  425.       data = stmt.row[field];
  426.     stmt.reset();
  427.     return data;
  428.   }
  429. }
  430.  
  431.  
  432. function flockBlogService() {
  433.   // For an observer on flock-data-ready for import
  434.   var obs = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
  435.   obs.addObserver(this, 'flock-data-ready', false);
  436.  
  437.   this.acUtils = Cc["@flock.com/account-utils;1"].getService(Ci.flockIAccountUtils);
  438.  
  439.   this.initialized = false;
  440. }
  441.  
  442.  
  443. flockBlogService.prototype.init =
  444. function()
  445. {
  446.   if (this.initialized)
  447.     return;
  448.  
  449.   gBlogStorage = new BlogStorage();
  450.  
  451.   this._coop = Cc['@flock.com/singleton;1'].getService(Ci.flockISingleton).getSingleton('chrome://browser/content/flock/common/load-faves-coop.js').wrappedJSObject;
  452.  
  453.   if (!this.needsMigration(null)) {
  454.     var prefsService = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService);
  455.     var blogBranch = prefsService.getBranch("flock.blog.");
  456.     var mozstorage = false;
  457.     try {
  458.       mozstorage = blogBranch.getBoolPref("mozstorage");
  459.     } catch(e) { /* The pref is not set yet */ }
  460.     if (!mozstorage) {
  461.       var draftsRoot = this._coop.get(FLOCK_DRAFTS_ROOT);
  462.       if (draftsRoot) {
  463.         // Migrate from RDF to mozstorage (0.9.0 => 0.9.1)
  464.         var folders = draftsRoot.children.enumerate();        
  465.         while (folders.hasMoreElements()) {
  466.           var folder = folders.getNext();
  467.           var blogid = "";
  468.           if (!folder.id().match('UnpublishedRoot')) {
  469.             blogid = folder.id().split(":folder:").pop();
  470.           }
  471.           var drafts = folder.children.enumerate();
  472.           while (drafts.hasMoreElements()) {
  473.             var draft = drafts.getNext();
  474.             // Add the draft to BlogStorage
  475.             var draftid = this.saveDraft(null, draft.name, draft.content, draft.tags);
  476.             this.moveTo(draftid, blogid);
  477.             // Then remove it from RDF
  478.             folder.children.remove(draft);
  479.             draft.destroy();
  480.           }
  481.           draftsRoot.children.remove(folder);
  482.           folder.destroy();
  483.         }
  484.         draftsRoot.destroy();
  485.       }
  486.       blogBranch.setBoolPref ("mozstorage", true);
  487.     }
  488.   }
  489.  
  490.   this.mName2ServiceMap = {};
  491.   this.mService2NameMap = {};
  492.  
  493.   // Logger
  494.   this.logger = Cc['@flock.com/logger;1'].createInstance(Ci.flockILogger);
  495.   this.logger.init("blogservice");
  496.  
  497.   // Add Technorati.com on first run
  498.   var prefsService = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService);
  499.   var blogBranch = prefsService.getBranch("flock.blog");
  500.   try {
  501.     var firstRun = blogBranch.getIntPref("firstRun");
  502.   } catch(e) {}
  503.   if (!firstRun) {
  504.     // TODO
  505.     //this.addNotification("http://www.technorati.com")
  506.     //blogBranch.setIntPref("firstRun", 1);
  507.     //blogBranch.setBoolPref("notify", true);
  508.   }
  509.  
  510.   // Search for registered blog web services
  511.   var catmgr = Cc["@mozilla.org/categorymanager;1"]
  512.       .getService (Ci.nsICategoryManager);
  513.   var enum_ = catmgr.enumerateCategory("flockICustomBlogWebService");
  514.   while(enum_.hasMoreElements()) {
  515.     var obj = enum_.getNext();
  516.     supportsString = obj.QueryInterface(Ci.nsISupportsCString);
  517.     var shortName = supportsString.toString();
  518.     var cid = catmgr.getCategoryEntry("flockICustomBlogWebService", shortName); 
  519.     var svc = Cc[cid].getService(Ci.flockICustomBlogWebService);
  520.     this.registerAPI(svc, shortName);
  521.   }
  522.  
  523.   this.initialized = true;
  524. }
  525.  
  526. //flockIMigratable
  527. flockBlogService.prototype.__defineGetter__('shortname', function() {
  528.   return "Blogging Accounts";
  529. });
  530.  
  531. flockBlogService.prototype.needsMigration =
  532. function (oldVersion)
  533. {
  534.   var oldShelfFile = Cc["@mozilla.org/file/directory_service;1"] 
  535.                        .getService(Ci.nsIProperties)
  536.                        .get("ProfD", Ci.nsIFile);
  537.   oldShelfFile.append(OLD_SHELF_RDF_FILE);
  538.  
  539.   var oldBlogFile = Cc["@mozilla.org/file/directory_service;1"] 
  540.                        .getService(Ci.nsIProperties)
  541.                        .get("ProfD", Ci.nsIFile);
  542.   oldBlogFile.append(OLD_BLOG_RDF_FILE);
  543.  
  544.   var relicBlogFile = Cc["@mozilla.org/file/directory_service;1"] 
  545.                        .getService(Ci.nsIProperties)
  546.                        .get("ProfD", Ci.nsIFile);
  547.   relicBlogFile.append(OLD_BLOG_RDF_FILE_RELIC);
  548.  
  549.   // only migrate if the old favorites rdf file exists
  550.   // FIXME: after the flock_favorites.rdf file is renamed to flock_favorites_old.rdf
  551.   // flock_favorites.rdf is created again in the same dir. so we need the 2nd
  552.   // condition in the IF to stop migration from happening again
  553.   if(oldBlogFile.exists() && !relicBlogFile.exists()) {
  554.     return true;
  555.   }
  556.   return false;
  557. }
  558.  
  559. flockBlogService.prototype.startMigration = 
  560. function(oldVersion, aFlockMigrationProgressListener)
  561. {
  562.   this.init();
  563.  
  564.   var shelf_svc = Cc['@mozilla.org/rdf/datasource;1?name=flock-shelf'].getService(Ci.flockIShelfService);
  565.  
  566.   var oldShelfFile = Cc["@mozilla.org/file/directory_service;1"] 
  567.                        .getService(Ci.nsIProperties)
  568.                        .get("ProfD", Ci.nsIFile);
  569.   oldShelfFile.append(OLD_SHELF_RDF_FILE);
  570.  
  571.   var oldBlogFile = Cc["@mozilla.org/file/directory_service;1"] 
  572.                        .getService(Ci.nsIProperties)
  573.                        .get("ProfD", Ci.nsIFile);
  574.   oldBlogFile.append(OLD_BLOG_RDF_FILE);
  575.  
  576.   var relicBlogFile = Cc["@mozilla.org/file/directory_service;1"] 
  577.                        .getService(Ci.nsIProperties)
  578.                        .get("ProfD", Ci.nsIFile);
  579.   relicBlogFile.append(OLD_BLOG_RDF_FILE_RELIC);
  580.  
  581.   var ctxt = {
  582.     listener: aFlockMigrationProgressListener,
  583.     oldShelfFile: oldShelfFile,
  584.     oldBlogFile: oldBlogFile
  585.   };
  586.  
  587.   if (oldBlogFile.exists())
  588.     ctxt.listener.onUpdate(0, 'Migrating blog settings');
  589.  
  590.   return { wrappedJSObject: ctxt };
  591. }
  592.  
  593. flockBlogService.prototype.finishMigration = 
  594. function(ctxtWrapper)
  595. {
  596. }
  597.  
  598. flockBlogService.prototype.doMigrationWork =
  599. function(ctxtWrapper)
  600. {
  601.   var ctxt = ctxtWrapper.wrappedJSObject;
  602.  
  603.   if (!ctxt.oldBlogFile.exists())
  604.     return false;
  605.  
  606.   if (!ctxt.blogMigrator)
  607.     ctxt.blogMigrator = this._migrateBlogs(ctxt);
  608.   if (ctxt.blogMigrator.next())
  609.     ctxt.blogMigrator = null;
  610.  
  611.   return Boolean(ctxt.blogMigrator);
  612. }
  613.  
  614. flockBlogService.prototype._migrateBlogs =
  615. function(ctxt)
  616. {
  617.   var blogsvc = this;
  618.   var acUtils = Cc["@flock.com/account-utils;1"].getService(Ci.flockIAccountUtils);
  619.  
  620.   function createAccountAndBlog (aServiceId, aServiceUrn, aUsername, aPassword, aBlogName, aBlogid, aUrl, aApilink) {
  621.     var svc = Cc[aServiceId].getService(Ci.flockIWebService);
  622.     svc.init();
  623.     acUtils.setPassword(svc.urn+":"+aUsername, aUsername, aPassword);
  624.  
  625.     var accountURN = svc.urn+":"+aUsername;
  626.     var account = new blogsvc._coop.Account(accountURN, {
  627.       name: aUsername,
  628.       serviceId: aServiceId,
  629.       service: blogsvc._coop.get(aServiceUrn),
  630.       accountId: aUsername,
  631.       favicon: svc.icon,
  632.       URL: svc.url
  633.     });
  634.     blogsvc._coop.accounts_root.children.addOnce(account);
  635.  
  636.     var theCoopBlog = new blogsvc._coop.Blog(accountURN+":"+aBlogid, {
  637.       name: aBlogName,
  638.       title: aBlogName,
  639.       blogid: aBlogid,
  640.       URL: aUrl,
  641.       apiLink: aApilink
  642.     });
  643.     account.children.addOnce(theCoopBlog);
  644.   }
  645.  
  646.   var rdfs = Cc["@mozilla.org/rdf/rdf-service;1"].getService (Ci.nsIRDFService);
  647.   var ios = Cc['@mozilla.org/network/io-service;1'].getService (Ci.nsIIOService);
  648.   var ds = rdfs.GetDataSourceBlocking(ios.newFileURI(ctxt.oldBlogFile).spec);
  649.  
  650.   var accountsRes = rdfs.GetResource("urn:flock:blog:settings");
  651.   var container = Cc["@mozilla.org/rdf/container;1"].createInstance(Ci.nsIRDFContainer);
  652.   container.Init(ds, accountsRes);
  653.  
  654.   var children = container.GetElements();
  655.   this.logger.info("Start migration of the blog accounts");
  656.   while (children.hasMoreElements()){
  657.     var child = children.getNext().QueryInterface(Ci.nsIRDFResource);
  658.     var apiRes = rdfs.GetResource(child.ValueUTF8 + ":api");
  659.  
  660.     var nameRes = rdfs.GetResource("http://www.flock.com/rdf#title");
  661.     var name = ds.GetTarget(child, nameRes, true).QueryInterface(Ci.nsIRDFLiteral).Value;
  662.  
  663.     this.logger.info("Found the blog: "+name+" for import");
  664.     ctxt.listener.onUpdate(0, "Migrating " + name);
  665.     yield false;
  666.  
  667.     var urlRes = rdfs.GetResource("http://www.flock.com/rdf#url");
  668.     var url = ds.GetTarget(child, urlRes, true).QueryInterface(Ci.nsIRDFLiteral).Value;
  669.  
  670.     var blogidRes = rdfs.GetResource("http://www.flock.com/rdf#blogid");
  671.     var blogid = ds.GetTarget(apiRes, blogidRes, true).QueryInterface(Ci.nsIRDFLiteral).Value;
  672.  
  673.     var apilinkRes = rdfs.GetResource("http://www.flock.com/rdf#apiLink");
  674.     var apilink = ds.GetTarget(apiRes, apilinkRes, true).QueryInterface(Ci.nsIRDFLiteral).Value;
  675.  
  676.     // Get the username/password...
  677.     var usernameRes = rdfs.GetResource("http://www.flock.com/rdf#username");
  678.     var username = ds.GetTarget(child, usernameRes, true).QueryInterface(Ci.nsIRDFLiteral).Value;
  679.     var password = "";
  680.     this.logger.info("    Username = "+username);
  681.     if (username != "") {
  682.       var pwhostRes = rdfs.GetResource("http://www.flock.com/rdf#pwhost");
  683.       var pwhost = ds.GetTarget(child, pwhostRes, true).QueryInterface(Ci.nsIRDFLiteral).Value;
  684.  
  685.       var password = getPassword(pwhost, username)
  686.     }
  687.     if (password == null || password == "") {
  688.       // The password was not stored or we couldn't find it
  689.       this.logger.info("    The password seems to be empty/unknown, let's ask the user");
  690.       var promptService = Cc['@mozilla.org/embedcomp/prompt-service;1'].getService(Ci.nsIPromptService);
  691.       var winMediator = Cc['@mozilla.org/appshell/window-mediator;1'].getService(Ci.nsIWindowMediator);
  692.  
  693.       var theUsername = {value: username};
  694.       var thePassword = {value: password};
  695.       promptService.promptUsernameAndPassword (
  696.           winMediator.getMostRecentWindow('navigator:browser'),
  697.           "Blog Account Import",
  698.           "Please enter your login information for "+name+"\n("+url+")",
  699.           theUsername, thePassword,
  700.           null, {value: false}
  701.       );
  702.       username = theUsername.value;
  703.       password = thePassword.value;
  704.     }
  705.     this.logger.info("   We finally have "+username+" and "+password);
  706.  
  707.     // The user pressed cancel or gave a blank password => don't add the blog
  708.     if (password == null || password == "")
  709.       break;
  710.     
  711.     // Now we can create the blog
  712.     if (url.match(/wordpress\.com/)) {
  713.       createAccountAndBlog ('@flock.com/people/wordpress;1', 'urn:wordpress:service', username, password,
  714.                             name, blogid, url, apilink);
  715.     }
  716.     else if (url.match(/livejournal\.com/)) {
  717.       apilink = 'http://www.livejournal.com/interface/xmlrpc';
  718.       createAccountAndBlog ('@flock.com/people/livejournal;1', 'urn:livejournal:service', username, password,
  719.                             name, blogid, url, apilink);
  720.     }
  721.     else if (url.match(/blogspot\.com/)) {
  722.       createAccountAndBlog ('@flock.com/people/blogger;1', 'urn:blogger:service', username, password,
  723.                             name, name, url, apilink);
  724.     }
  725.     else if (url.match(/typepad\.com/)) {
  726.       createAccountAndBlog ('@flock.com/blog/typepad;1', 'urn:typepad:service', username, password,
  727.                             name, blogid, url, apilink);
  728.     }
  729.     else { // Custom blog
  730.       try {
  731.         var apiRes = rdfs.GetResource("http://www.flock.com/rdf#api");
  732.         var api = ds.GetTarget(child, apiRes, true).QueryInterface(Ci.nsIRDFResource);
  733.         var apinameRes = rdfs.GetResource("http://www.flock.com/rdf#apiname");
  734.         var apiname = ds.GetTarget(api, apinameRes, true).QueryInterface(Ci.nsIRDFLiteral);
  735.         var blogidRes = rdfs.GetResource("http://www.flock.com/rdf#blogid");
  736.         var blogid = ds.GetTarget(api, blogidRes, true).QueryInterface(Ci.nsIRDFLiteral);
  737.         var apiLinkRes = rdfs.GetResource("http://www.flock.com/rdf#apiLink");
  738.         var apiLink = ds.GetTarget(api, apiLinkRes, true).QueryInterface(Ci.nsIRDFLiteral);
  739.  
  740.         // Create a custom account...
  741.         var customURN = "urn:flock:customblog:"+name;
  742.         if (!this._coop.Account.exists (customURN)) {
  743.           var custom = new this._coop.Account(customURN, {
  744.             name : name,
  745.             accountId : username,
  746.             serviceId: '@flock.com/blog/service/'+apiname.Value+';1',
  747.             URL : url,
  748.             favicon: 'http://'+url.split('/')[2]+'/favicon.ico'
  749.           });
  750.           var root = this._coop.get("http://flock.com/rdf#AccountsRoot");
  751.           root.children.add(custom);
  752.         }
  753.  
  754.         // ...save the password in the password manager...
  755.         var blogURN = customURN+":"+name;
  756.         var acUtils = Cc["@flock.com/account-utils;1"].getService(Ci.flockIAccountUtils);
  757.         acUtils.setPassword(customURN, username, password);
  758.         // ...and create a new blog as a child
  759.         theCoopBlog = new this._coop.Blog(blogURN, {
  760.           name: name,
  761.           title: name,
  762.           blogid: blogid.Value,
  763.           URL: url,
  764.           apiLink: apiLink.Value,
  765.         });
  766.         custom.children.addOnce(theCoopBlog);
  767.       }
  768.       catch(e) {
  769.         debug(e);
  770.       }
  771.     }
  772.   }
  773.  
  774.   // Import web snippets (shelf)
  775.   // debug("Import web snippets\n");
  776.   var shelf_svc = Cc['@mozilla.org/rdf/datasource;1?name=flock-shelf'].getService(Ci.flockIShelfService);
  777.   var shelfDS = rdfs.GetDataSourceBlocking(ios.newFileURI(ctxt.oldShelfFile).spec);
  778.   var shelfRes = rdfs.GetResource("urn:flock:shelf:objects");
  779.   var container = Cc["@mozilla.org/rdf/container;1"].createInstance(Ci.nsIRDFContainer);
  780.   container.Init(shelfDS, shelfRes);
  781.  
  782.   var importFolderId;
  783.   var children = container.GetElements();
  784.   while (children.hasMoreElements()){
  785.     var child = children.getNext().QueryInterface(Ci.nsIRDFResource);
  786.  
  787.     var nameRes = rdfs.GetResource("http://www.flock.com/rdf/shelf#title");
  788.     var name = shelfDS.GetTarget(child, nameRes, true).QueryInterface(Ci.nsIRDFLiteral);
  789.  
  790.     var contentRes = rdfs.GetResource("http://www.flock.com/rdf/shelf#content");
  791.     var content = shelfDS.GetTarget(child, contentRes, true).QueryInterface(Ci.nsIRDFLiteral);
  792.  
  793.     var urlRes = rdfs.GetResource("http://www.flock.com/rdf/shelf#url");
  794.     var url = shelfDS.GetTarget(child, urlRes, true).QueryInterface(Ci.nsIRDFLiteral);
  795.  
  796.     var typeRes = rdfs.GetResource("http://www.flock.com/rdf/shelf#type");
  797.     var type = shelfDS.GetTarget(child, typeRes, true).QueryInterface(Ci.nsIRDFLiteral);
  798.     var myType;
  799.     if (type.Value == "note") {
  800.       // The "note" type is deprecated
  801.       myType = "document";
  802.     } else {
  803.       myType = type.Value;
  804.     }
  805.  
  806.     debug(importFolderId+"\n");
  807.     ctxt.listener.onUpdate(0, 'Importing clipping: ' + name.Value);
  808.     shelf_svc.insert(name.Value, content.Value, url.Value, myType, -1, null);
  809.   }
  810.   // debug("Done with 'Import web snippets'\n");
  811.  
  812.   // Import blog posts
  813.   var prefs = Cc["@mozilla.org/preferences-service;1"]
  814.               .getService(Ci.nsIPrefService)
  815.               .getBranch("flock.blog.");
  816.   var init_dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
  817.  
  818.   try {
  819.     var value = prefs.getComplexValue("saveLocation", Ci.nsISupportsString).data;
  820.   } catch(e) {}
  821.  
  822.     if (value) {
  823.  
  824.     init_dir.initWithPath(value);
  825.     var importDraftsFolderId;
  826.     var enum = init_dir.directoryEntries;
  827.     while (enum.hasMoreElements()) {
  828.       var file = enum.getNext().QueryInterface(Ci.nsILocalFile);
  829.  
  830.       try {
  831.         // Get the content of the file
  832.         var instream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);    
  833.         var scriptinstream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(Ci.nsIScriptableInputStream);
  834.         instream.init(file, 0x01, 00400 | 00200 | 00040 | 00004, 0);
  835.         scriptinstream.init(instream);
  836.         var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
  837.         converter.charset = "UTF-8";
  838.         var result = scriptinstream.read(scriptinstream.available());
  839.         var finalresult; // Mark is getting an exception around here
  840.         finalresult = converter.ConvertToUnicode(result);
  841.         finalresult += converter.Finish();
  842.         scriptinstream.close();
  843.  
  844.         // Separate the title from the content
  845.         var theTitle = finalresult.substring(0, finalresult.indexOf('\n'));
  846.         theTitle = theTitle.replace(/<h1>/, '').replace(/<\/h1>/, '');
  847.         var theBody = finalresult.substring(finalresult.indexOf('\n')+1, finalresult.length);
  848.  
  849.         // Add to the drafts
  850.         var newId = this.saveDraft(null, theTitle, theBody, "");
  851.         this.moveTo(newId, "imported");
  852.       }
  853.       catch(e) {
  854.         // TODO: give feedback to the user, saying we failed to import one draft
  855.         debug("**** Error while importing the blog draft: "+file.path+". I will just ignore this draft and go on.\n\n"+e+"\n");
  856.       }
  857.     }
  858.   }
  859.  
  860.   // Set this pref to prevent 0.9.0 => 0.9.1 migration to happen
  861.   prefs.setBoolPref ("mozstorage", true);
  862.  
  863.   // rename the file and delete the old copy
  864.   rdfs.UnregisterDataSource(ds);
  865.   ds = null;
  866.   
  867.   ctxt.oldBlogFile.moveTo(null, OLD_BLOG_RDF_FILE_RELIC);
  868.   yield true;
  869. }
  870.  
  871. // nsIObserver
  872. flockBlogService.prototype.observe =
  873. function(subject, topic, state)
  874. {
  875.   switch (topic) {
  876.     case 'flock-data-ready':
  877.       var obs = Cc["@mozilla.org/observer-service;1"]
  878.         .getService(Ci.nsIObserverService);
  879.       obs.removeObserver(this, 'flock-data-ready');
  880.       this.init();
  881.       return;
  882.   }
  883. }
  884.  
  885.  
  886. // nsISimpleEnumerator implementation
  887. function simpleEnumerator (aArray)
  888. {
  889.   aArray.hasMoreElements = function () { 
  890.     return this.length != 0; 
  891.   }
  892.   aArray.getNext = function () { 
  893.     var rval = this.shift (); 
  894.     return rval;
  895.   }
  896.   return aArray;
  897. }
  898.  
  899. // nsIStringEnumerator implementation
  900. function stringEnumerator (aArray)
  901. {
  902.   aArray.hasMore = function () { 
  903.     return this.length != 0; 
  904.   }
  905.   aArray.getNext = function () { 
  906.     var rval = this.shift (); 
  907.     return rval;
  908.   }
  909.   return aArray;
  910. }
  911.  
  912. loadLibraryFromSpec('chrome://browser/content/flock/contrib/rdfds.js');
  913.  
  914. function loadLibraryFromSpec(aSpec)
  915. {
  916.   var loader = Cc['@mozilla.org/moz/jssubscript-loader;1']
  917.     .getService(Ci.mozIJSSubScriptLoader);
  918.  
  919.   loader.loadSubScript(aSpec);
  920. }
  921.  
  922.  
  923. function getPassword(aHost, aUsername)
  924. {
  925.   var psm = Cc["@mozilla.org/passwordmanager;1"].getService(Ci.nsIPasswordManager);
  926.   var enum = psm.enumerator;
  927.   while(enum.hasMoreElements()) {
  928.     var pw = enum.getNext();
  929.     pw = pw.QueryInterface(Ci.nsIPassword);
  930.     if(pw.host==aHost && aUsername==pw.user) {
  931.       return pw.password;
  932.     }
  933.   }
  934.   return null;
  935. }
  936.  
  937. // Ensure that the "recent" list as no more than BLOG_RECENT_COUNT elements
  938. flockBlogService.prototype.cleanRecent = function () {
  939.   debug("*** flockBlogService.addRecent: NOT IMPLEMENTED. TO IT NOW!! ***\n");
  940. }
  941.  
  942. // the flockIBlogService implementation
  943.  
  944. flockBlogService.prototype.accountExists = function (aTitle) { 
  945.   var accounts = this._coop.Blog.find({ title: aTitle });
  946.   return (accounts.length > 0); 
  947. }
  948.  
  949.  
  950. flockBlogService.prototype.accountCount = function () {
  951.   var count = 0;
  952.   var accounts = this._coop.get('http://flock.com/rdf#AccountsRoot');
  953.   var enum = accounts.children.enumerate();
  954.   while (enum.hasMoreElements()) {
  955.     var account = enum.getNext();
  956.     if (account) {
  957.       var enum2 = account.children.enumerate();
  958.       while (enum2.hasMoreElements())
  959.         if (enum2.getNext().isInstanceOf(this._coop.Blog))
  960.           ++count;
  961.     }
  962.   }
  963.   return count;
  964. }
  965.  
  966.  
  967. flockBlogService.prototype.getAccountList = function () {
  968.   var result = new Array();
  969.  
  970.   var accounts = this._coop.get('http://flock.com/rdf#AccountsRoot');
  971.   var enum = accounts.children.enumerate();
  972.   while (enum.hasMoreElements()) {
  973.     var account = enum.getNext();
  974.     var enum2 = account.children.enumerate();
  975.     while (enum2.hasMoreElements()) {
  976.       var child = enum2.getNext();
  977.       if (child.isInstanceOf(this._coop.Blog))
  978.         result.push(child);
  979.     }
  980.   }
  981.  
  982.   return simpleEnumerator(result);
  983. }
  984.  
  985.  
  986. flockBlogService.prototype.getDefaultBlog = function () { 
  987.   var prefs = Components.classes["@mozilla.org/preferences-service;1"]
  988.                 .getService(Components.interfaces.nsIPrefService)
  989.                 .getBranch("flock.blog.");
  990.   var value = null;
  991.   try{
  992.     value = prefs.getCharPref ("defaultblog");
  993.   } catch(e) {
  994.     return "";
  995.   }
  996.   return value;
  997. }
  998.  
  999.  
  1000. flockBlogService.prototype.setDefaultBlog = function (aValue) { 
  1001.   var prefs = Components.classes["@mozilla.org/preferences-service;1"]
  1002.                 .getService(Components.interfaces.nsIPrefService)
  1003.                 .getBranch("flock.blog.");
  1004.   prefs.setCharPref ("defaultblog", aValue);
  1005. }
  1006.  
  1007.  
  1008.  
  1009. flockBlogService.prototype.addRecent = function (aName, aFile) { 
  1010.   debug("*** flockBlogService.addRecent: NOT IMPLEMENTED. TO IT NOW!! ***\n");
  1011. }
  1012.  
  1013.  
  1014. flockBlogService.prototype.recentIsEmpty =
  1015. function ()
  1016.   debug("*** flockBlogService.recentIsEmpty: NOT IMPLEMENTED. TO IT NOW!! ***\n");
  1017. }
  1018.  
  1019.  
  1020. flockBlogService.prototype.registerAPI =
  1021. function(aService, aShortname)
  1022. {
  1023.   this.mName2ServiceMap[aShortname] = aService;
  1024.   this.mService2NameMap[aService] = aShortname;
  1025. }
  1026.  
  1027.  
  1028. flockBlogService.prototype.getAPIFromShortname =
  1029. function(aShortname)
  1030. {
  1031.   for (i in this.mName2ServiceMap) {
  1032.     debug(i+": "+this.mName2ServiceMap[i]+"\n");
  1033.   }
  1034.   return this.mName2ServiceMap[aShortname];
  1035. }
  1036.  
  1037.  
  1038. flockBlogService.prototype.getShortnameFromAPI =
  1039. function(aService)
  1040. {
  1041.   return this.mService2NameMap[aService];
  1042. }
  1043.  
  1044.  
  1045. flockBlogService.prototype.__defineGetter__('services', function ()
  1046. {
  1047.   var ar = new Array();
  1048.   for(var p in this.mName2ServiceMap) {
  1049.     ar.push(this.mName2ServiceMap[p]);
  1050.   }
  1051.   var rval = {
  1052.     getNext: function() {
  1053.       var rval = ar.shift();
  1054.       return rval;
  1055.     },
  1056.     hasMoreElements: function() {
  1057.       return (ar.length>0);
  1058.     },
  1059.   }
  1060.   return rval;
  1061. })
  1062.  
  1063.  
  1064. flockBlogService.prototype.getCandidatesAPI =
  1065. function(aListener, aUrl)
  1066. {
  1067.   var detector = new BlogAPIDetector();
  1068.   detector.detect(aListener, aUrl);
  1069. }
  1070.  
  1071.  
  1072. flockBlogService.prototype.saveAccount =
  1073. function (aParentId, aId, aBlogAccount)
  1074. {
  1075.   // Get or create the coop object
  1076.   var account = null;
  1077.   if (aId) {
  1078.     account = this._coop.get(aId);
  1079.     if (!account)
  1080.       account = new this._coop.Blog(aId);
  1081.   }
  1082.   else
  1083.     account = new this._coop.Blog(aParentId+":"+aBlogAccount.username);
  1084.  
  1085.   // Save the password in the password manager
  1086.   var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
  1087.   var uri = ios.newURI(aBlogAccount.URL, null, null);
  1088.   var pwhost = "flockinternal." + uri.host;
  1089.   if(aBlogAccount.username && aBlogAccount.username.length) {
  1090.     var psm = Cc["@mozilla.org/passwordmanager;1"].getService(Ci.nsIPasswordManager);
  1091.     psm.addUser(pwhost, aBlogAccount.username, aBlogAccount.password);
  1092.   }
  1093.  
  1094.   // Save the rest in flock-data
  1095.   account.title = aBlogAccount.title;
  1096.   account.name = aBlogAccount.title;
  1097.   account.favicon = aBlogAccount.favicon;
  1098.   account.username = aBlogAccount.username;
  1099.   account.URL = aBlogAccount.URL;
  1100.   account.pwhost = pwhost;
  1101.   account.api = aBlogAccount.api;
  1102.   account.apiLink = aBlogAccount.apiLink;
  1103.   account.blogid = aBlogAccount.blogid;
  1104.   account.authtoken = aBlogAccount.authtoken;
  1105.  
  1106.   var parent = this._coop.get(aParentId);
  1107.   parent.children.add(account);
  1108. }
  1109.  
  1110. flockBlogService.prototype.getAccount = function (aBlogID) {
  1111.   if(!aBlogID) throw new Error("Error in BlogSettings.getAccount()");
  1112.   var coopblog = this._coop.get(aBlogID);
  1113.   var coopaccount = coopblog.getParent();
  1114.  
  1115.   if (coopaccount) {
  1116.     // var password = getPassword(coopaccount.id()+":"+coopaccount.accountId, coopaccount.accountId);
  1117.     debug(" ^^^^^^^^^ Get the password for "+coopaccount.id()+"\n");
  1118.     var pw = this.acUtils.getPassword(coopaccount.id());
  1119.     if (pw)
  1120.       var password = pw.password;
  1121.     debug("++++++ Found the password: "+password+"\n");
  1122.   }
  1123.  
  1124.   var account = {
  1125.     blogid: coopblog.blogid,
  1126.     username: coopaccount.accountId,
  1127.     password: password,
  1128.     authtoken: coopblog.authtoken,
  1129.     apiLink: coopblog.apiLink,
  1130.     getInterfaces: function (count) {
  1131.       var interfaceList = [Ci.flockIBlogAccount, Ci.nsIClassInfo];
  1132.       count.value = interfaceList.length;
  1133.       return interfaceList;
  1134.     },
  1135.     QueryInterface: function (iid) {
  1136.       if (!iid.equals(Ci.flockIBlogAccount))
  1137.         throw Cr.NS_ERROR_NO_INTERFACE;
  1138.       return this;
  1139.     }
  1140.   }
  1141.  
  1142.   return account;
  1143. };
  1144.  
  1145.  
  1146. flockBlogService.prototype.getBlogAPI = function (aBlogID) {
  1147.   try {
  1148.     var account = this._coop.get(aBlogID);
  1149.  
  1150.     return this.getAPIFromShortname(account.api);
  1151.   }
  1152.   catch(e) {
  1153.     debug("Caught exception: "+e+" "+e.fileName+" "+e.lineNumber+"\n");
  1154.     return null;
  1155.   }
  1156. };
  1157.  
  1158. flockBlogService.prototype.addCategory = function (aBlogID, aCategoryId, aCategoryName) {
  1159.   var account = this._coop.get(aBlogID);
  1160.   var enum = account.categories.enumerate();
  1161.   var category = null;
  1162.   while (enum.hasMoreElements()) {
  1163.     var cat = enum.getNext();
  1164.     if (cat.categoryId == aCategoryId)
  1165.       category = cat;
  1166.   }
  1167.   if (!category) {
  1168.     category = new this._coop.BlogCategory();
  1169.     category.categoryId = aCategoryId;
  1170.   }
  1171.   category.name = aCategoryName
  1172.   category.save();
  1173.  
  1174.   account.categories.addOnce(category);
  1175. };
  1176.  
  1177. flockBlogService.prototype.flushCategories = function (aBlogAccount) {
  1178.   debug("*** flockBlogService.flushCategories: DEPRECATED. DON'T USE IT!! ***\n");
  1179. };
  1180.  
  1181. flockBlogService.prototype.addNotification = function (aURL) {
  1182.   debug("*** flockBlogService.addNotification: NOT IMPLEMENTED. DO IT NOW!! ***\n");
  1183. };
  1184.  
  1185. flockBlogService.prototype.removeNotification = function (aURL) {
  1186.   debug("*** flockBlogService.removeNotification: NOT IMPLEMENTED. DO IT NOW!! ***\n");
  1187. };
  1188.  
  1189.  
  1190. flockBlogService.prototype.getNotifications = function () {
  1191.   debug("*** flockBlogService.recentIsEmpty: NOT IMPLEMENTED. DO IT NOW!! ***\n");
  1192.   return stringEnumerator([]);
  1193. };
  1194.  
  1195.  
  1196. flockBlogService.prototype._openBlogEditor =
  1197. function (aParams) {
  1198.   // Recover if needed
  1199.   var needRecovery = false;
  1200.   if (!this.editorIsOpen()) {
  1201.     var _enum = this.getAllRecovery();
  1202.     if (_enum.hasMoreElements()) // There is at least one recovered draft
  1203.       needRecovery = true;
  1204.   }
  1205.  
  1206.   if (needRecovery) {
  1207.     var wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
  1208.     var win = wm.getMostRecentWindow('navigator:browser');
  1209.     win.openDialog("chrome://browser/content/flock/blog/blogRecovery.xul", "openRecovery", "chrome,modal,centerscreen", null);
  1210.   }
  1211.   var ww = Cc['@mozilla.org/embedcomp/window-watcher;1'].getService(Ci.nsIWindowWatcher);
  1212.   return ww.openWindow(null, EDITOR_URL, "_blank", "chrome,close,titlebar,resizable=yes,toolbar=no,dialog=no,scrollbars=yes", aParams);
  1213. }
  1214.  
  1215.  
  1216. flockBlogService.prototype.openPost =
  1217. function (aId) {
  1218.   var windowMediator = Components.classes["@mozilla.org/appshell/window-mediator;1"]
  1219.     .getService(Components.interfaces.nsIWindowMediator);
  1220.  
  1221.   // See if the post is not already open
  1222.   var oldWin = null;
  1223.   
  1224.   var singleUploadWindow = false;
  1225.   var allWindows = windowMediator.getEnumerator(null);
  1226.   debug("Looking for {"+aId+"}\n");
  1227.   while (allWindows.hasMoreElements() && !oldWin) {
  1228.     var win = allWindows.getNext();
  1229.     if (win.gDraftId && (win.gDraftId == aId)) {
  1230.       oldWin = win;
  1231.     }
  1232.   }
  1233.  
  1234.   if (oldWin) { // Bring the existing window to the front
  1235.     oldWin.focus();
  1236.   }
  1237.   else { // Open a new window
  1238.     var params = Cc["@mozilla.org/embedcomp/dialogparam;1"].createInstance(Ci.nsIDialogParamBlock);
  1239.     params.SetNumberStrings(4);
  1240.     params.SetString(0, aId);
  1241.     params.SetString(1, "");
  1242.     params.SetString(2, "");
  1243.     params.SetString(3, "");
  1244.  
  1245.     this._openBlogEditor(params);
  1246.   }
  1247. }
  1248.  
  1249.  
  1250. flockBlogService.prototype.openEditor =
  1251. function (aTitle, aContent, aTags) {
  1252.   var setup = 1; // Default to "Cancel"
  1253.  
  1254.   if (this.accountCount() == 0) {
  1255.     // Tell the user to configure an account
  1256.     var wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
  1257.     var win = wm.getMostRecentWindow('navigator:browser');
  1258.     var ps = Cc["@mozilla.org/embedcomp/prompt-service;1"]
  1259.              .getService(Ci.nsIPromptService);
  1260.     var sbs = Cc["@mozilla.org/intl/stringbundle;1"]
  1261.               .getService(Ci.nsIStringBundleService);
  1262.     var sb = sbs.createBundle("chrome://flock/locale/blog/blog.properties");
  1263.     var brand = sbs.createBundle("chrome://branding/locale/brand.properties");
  1264.  
  1265.     var flags = Ci.nsIPromptService.BUTTON_TITLE_IS_STRING *
  1266.                 Ci.nsIPromptService.BUTTON_POS_0 +
  1267.                 Ci.nsIPromptService.BUTTON_TITLE_CANCEL *
  1268.                 Ci.nsIPromptService.BUTTON_POS_1 +
  1269.                 Ci.nsIPromptService.BUTTON_TITLE_IS_STRING *
  1270.                 Ci.nsIPromptService.BUTTON_POS_2;
  1271.  
  1272.     var title = sb.GetStringFromName("flock.blog.account.req.title");
  1273.     var button1 = sb.GetStringFromName("flock.blog.account.req.setupButton");
  1274.     var appName = brand.GetStringFromName("brandShortName");
  1275.     var button3 = sb.GetStringFromName("flock.blog.account.req.continueButton");
  1276.     var substitutions = [button1, appName, button3];
  1277.     var bodyText = sb.formatStringFromName("flock.blog.account.req.text",
  1278.                                            substitutions,
  1279.                                            substitutions.length);
  1280.  
  1281.     setup = ps.confirmEx(win,
  1282.                          title,
  1283.                          bodyText,
  1284.                          flags,
  1285.                          button1,
  1286.                          null,
  1287.                          button3,
  1288.                          null,
  1289.                          {});
  1290.   }
  1291.   else {
  1292.     setup = 2;
  1293.   }
  1294.  
  1295.   switch (setup) {
  1296.   case 0:
  1297.     // "Setup Account"
  1298.     win.flock_blogLaunchSettings();
  1299.     break;
  1300.   case 2:
  1301.     // "Continue"
  1302.     //dump("aContent = "+aContent+"\n");
  1303.     var params = Cc["@mozilla.org/embedcomp/dialogparam;1"].createInstance(Ci.nsIDialogParamBlock);
  1304.     params.SetNumberStrings(4);
  1305.     params.SetString(0, "");
  1306.     params.SetString(1, aTitle?aTitle:"");
  1307.     params.SetString(2, aContent?aContent:"");
  1308.     params.SetString(3, aTags?aTags:"");
  1309.     return this._openBlogEditor(params);
  1310.   default:
  1311.     // Cancel
  1312.   }
  1313.   return null;
  1314. }
  1315.  
  1316.  
  1317. flockBlogService.prototype.editorIsOpen =
  1318. function () {
  1319.   var wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
  1320.   return (!!wm.getMostRecentWindow("Flock:BlogEditor"));
  1321. }
  1322.  
  1323.  
  1324. flockBlogService.prototype.saveDraft =
  1325. function (aId, aTitle, aContent, aTags) {
  1326.   var now = (new Date()).getTime();
  1327.   var id = (aId && aId > 0)?aId:(now * 100 + Math.floor(Math.random() * 100));
  1328.   
  1329.   gBlogStorage.saveDraft(id, now, aTitle, aContent, aTags);
  1330.   return id;
  1331. }
  1332.  
  1333. flockBlogService.prototype.saveRecovery =
  1334. function (aId, aTitle, aContent, aTags) {
  1335.   var now = (new Date()).getTime();
  1336.   var id = (aId && aId > 0)?aId:(now * 100 + Math.floor(Math.random() * 100));
  1337.  
  1338.   gBlogStorage.saveRecovery(id, now, aTitle, aContent, aTags);
  1339.   return id;
  1340. }
  1341.  
  1342. flockBlogService.prototype.getDraft =
  1343. function flockBlogService_getDraft (aDraftId) {
  1344.   return gBlogStorage.getDraft(aDraftId);
  1345. }
  1346.  
  1347. flockBlogService.prototype.getDraftsFrom =
  1348. function flockBlogService_getDraftsFrom (aBlogId) {
  1349.   var drafts = gBlogStorage.getDraftsFrom (aBlogId);
  1350.   return simpleEnumerator(drafts);
  1351. }
  1352.  
  1353. flockBlogService.prototype.moveTo =
  1354. function flockBlogService_moveTo (aId, aBlogId) {
  1355.   gBlogStorage.setDraftBlog(aId, aBlogId);
  1356. }
  1357.  
  1358.  
  1359. flockBlogService.prototype.removeDraft =
  1360. function (aId) {
  1361.   gBlogStorage.deleteDraft(aId);
  1362. }
  1363.  
  1364.  
  1365. flockBlogService.prototype.removeRecovery =
  1366. function (aId) {
  1367.   gBlogStorage.deleteRecovery(aId);
  1368. }
  1369.  
  1370.  
  1371. flockBlogService.prototype.looseRecovery =
  1372. function () {
  1373.   gBlogStorage.emptyRecovery();
  1374. }
  1375.  
  1376. flockBlogService.prototype.getAllRecovery =
  1377. function flockBlogService_getAllRecovery () {
  1378.   var recoveries = gBlogStorage.getAllRecovery ();
  1379.   return simpleEnumerator(recoveries);
  1380. }
  1381.  
  1382.  
  1383. flockBlogService.prototype.flags = Ci.nsIClassInfo.SINGLETON;
  1384. flockBlogService.prototype.classDescription = "Flock Blog Service";
  1385. flockBlogService.prototype.getInterfaces = function (count) {
  1386.     var interfaceList = [Ci.flockIBlogService, Ci.flockIMigratable,
  1387.                          Ci.nsIObserver, Ci.nsIClassInfo];
  1388.     count.value = interfaceList.length;
  1389.     return interfaceList;
  1390. }
  1391. flockBlogService.prototype.getHelperForLanguage = function (count) {return null;}
  1392.  
  1393. // the nsISupports implementation
  1394. flockBlogService.prototype.QueryInterface =
  1395. function (iid) {
  1396.     if (!iid.equals(Ci.flockIBlogService) && 
  1397.         !iid.equals(Ci.flockIMigratable) &&
  1398.         !iid.equals(Ci.nsIClassInfo) &&
  1399.         !iid.equals(Ci.nsIObserver) &&
  1400.         !iid.equals(Ci.nsISupports))
  1401.         throw Cr.NS_ERROR_NO_INTERFACE;
  1402.     return this;
  1403. }
  1404.  
  1405. // Module implementation
  1406. var BlogModule = new Object();
  1407.  
  1408. BlogModule.registerSelf =
  1409. function (compMgr, fileSpec, location, type)
  1410. {
  1411.     compMgr = compMgr.QueryInterface(Ci.nsIComponentRegistrar);
  1412.  
  1413.     compMgr.registerFactoryLocation(FLOCK_BLOG_CID, 
  1414.                                     "Flock Blog JS Component",
  1415.                                     FLOCK_BLOG_CONTRACTID, 
  1416.                                     fileSpec, 
  1417.                                     location,
  1418.                                     type);
  1419.  
  1420.     // Make the blog service a startup observer (for migration)
  1421.     var categoryManager = Cc["@mozilla.org/categorymanager;1"]
  1422.       .getService(Ci.nsICategoryManager);
  1423.     categoryManager.addCategoryEntry("flock-startup", "Flock Blog Service", "service," + FLOCK_BLOG_CONTRACTID, true, true);
  1424.     categoryManager.addCategoryEntry('flockMigratable', 'blogservice', FLOCK_BLOG_CONTRACTID, true, true);
  1425. }
  1426.  
  1427. BlogModule.getClassObject =
  1428. function (compMgr, cid, iid) {
  1429.     if (!cid.equals(FLOCK_BLOG_CID))
  1430.         throw Cr.NS_ERROR_NO_INTERFACE;
  1431.     
  1432.     if (!iid.equals(Ci.nsIFactory))
  1433.         throw Cr.NS_ERROR_NOT_IMPLEMENTED;
  1434.     
  1435.     return BlogServiceFactory;
  1436. }
  1437.  
  1438. BlogModule.canUnload =
  1439. function(compMgr)
  1440. {
  1441.     return true;
  1442. }
  1443.     
  1444. /* factory object */
  1445. var BlogServiceFactory = new Object();
  1446.  
  1447. BlogServiceFactory.createInstance =
  1448. function (outer, iid) {
  1449.     if (outer != null)
  1450.         throw Cr.NS_ERROR_NO_AGGREGATION;
  1451.  
  1452.     return (new flockBlogService()).QueryInterface(iid);
  1453. }
  1454.  
  1455. /* entrypoint */
  1456. function NSGetModule(compMgr, fileSpec) {
  1457.     return BlogModule;
  1458. }
  1459.